# == Schema Information
# Schema version: 11
#
# Table name: postings
#
#  id                       :integer(11)     not null, primary key
#  key                      :string(255)     
#  member_key               :string(255)     
#  group_key                :string(255)     
#  listing_number           :integer(11)     
#  title                    :string(255)     
#  primary_image_url        :string(255)     
#  amount_requested         :decimal(15, 4)  
#  borrower_rate            :decimal(15, 4)  
#  percent_funded           :float           
#  bid_count                :integer(11)     default(0)
#  end_date                 :datetime        
#  borrower_apr             :decimal(15, 4)  
#  credit_grade             :integer(11)     
#  is_borrower_homeowner    :boolean(1)      
#  is_bank_account_verified :boolean(1)      
#  debt_to_income_ratio     :decimal(15, 4)  
#  description              :string(255)     
#  status                   :integer(11)     
#  funding_option           :integer(11)     
#  borrower_state           :string(255)     
#  start_date               :datetime        
#  duration                 :integer(11)     
#  amount_funded            :decimal(15, 4)  
#  amount_remaining         :decimal(15, 4)  
#  bid_maximum_rate         :decimal(15, 4)  
#  borrower_maximum_rate    :decimal(15, 4)  
#  group_leader_reward_rate :decimal(15, 4)  
#  created_at               :datetime        
#  updated_at               :datetime        
#


class Posting < ActiveRecord::Base

  API_TO_MODEL = {
    "key"                   => :key,
    "memberKey"             => :member_key,
    "groupKey"              => :group_key,
    "listingNumber"         => :listing_number,
    "title"                 => :title,
    "primaryImageURL"       => :primary_image_url,
    "amountRequested"       => :amount_requested,
    "borrowerRate"          => :borrower_rate,
    "percentFunded"         => :percent_funded,
    "bidCount"              => :bid_count,
    "endDate"               => :end_date,
    "borrowerAPR"           => :borrower_apr,
    "creditGrade"           => :credit_grade,
    "isBorrowerHomeowner"   => :is_borrower_homeowner,
    "isBankAccountVerified" => :is_bank_account_verified,
    "debtToIncomeRatio"     => :debt_to_income_ratio,
    "description"           => :description,
    "status"                => :status,
    "fundingOption"         => :funding_option,
    "borrowerState"         => :borrower_state,
    "startDate"             => :start_date,
    "duration"              => :duration,
    "amountFunded"          => :amount_funded,
    "amountRemaining"       => :amount_remaining,
    "bidMaximumRate"        => :bid_maximum_rate,
    "borrowerMaximumRate"   => :borrower_maximum_rate,
    "groupLeaderRewardRate" => :group_leader_reward_rate,
    "creationDate"          => :created_at,
    "lastModifiedDate"      => :updated_at
  }.freeze

  CREDIT_GRADES = {
    0 => 'NC',
    1 => 'HR',
    2 => 'E',
    3 => 'D',
    4 => 'C',
    5 => 'B',
    6 => 'A',
    7 => 'AA'
  }.freeze
  
  CREDIT_SCORES = CREDIT_GRADES.invert
  
  has_many :bundlings
  has_many :bundles, :through => :bundlings
  
  validates_presence_of :key,
                        :member_key,
                        :listing_number,
                        :title,
                        :amount_requested,
                        :borrower_rate,
                        :percent_funded,
                        :bid_count,
                        :end_date,
                        :borrower_apr,
                        :credit_grade,
                        :description
  
  validates_numericality_of :listing_number,
                          	:amount_requested,
                          	:borrower_rate,
                          	:percent_funded,
                          	:borrower_apr,
                          	:credit_grade,
                          	:debt_to_income_ratio,
                          	:allow_blank => true
  
  validates_inclusion_of  :is_borrower_homeowner,
                          :is_bank_account_verified,
                          :in => [true, false]
                          
  validates_uniqueness_of :key
  
  # before_save :ensure_times_are_utc
  
  #overwrite the credit_grade field to a grade letter
  def credit_grade
    CREDIT_GRADES[read_attribute(:credit_grade)]
  end
  
  def time_left
    start_date - (duration - 1).days
  end
  
  def update_from_prosper
    update_attributes attributes_from_listing(ProsperAPIClient.retrieve('Listing', [key]))
  end
  
  def attributes_from_listing(listing)
    self.class.attributes_from_listing(listing)
  end
  
  class << self
    def new_from_prosper(listing)
      new(attributes_from_listing(listing))
    end
    
    def newest
      find(:first, :order => 'created_at DESC')
    end
        
    def attributes_from_listing(listing)
      API_TO_MODEL.keys.inject({}) { |result, attrib| result[API_TO_MODEL[attrib]] = listing.send(attrib); result }
    end
    
    def load_new_since(date)
      exclude_listings = find(:all, :select => '`key`', :conditions => ['created_at >= ?', date]).map(&:key)
      conditions = [("key != ? AND " * exclude_listings.size) + "creationDate >= ?"]
      conditions += exclude_listings << date.to_s(:soap)
      fetch_and_create(conditions)
    end
    
    def load_newer(limit=nil)
      return load_new_since(6.hours.ago) unless newest
      fetch_and_create(["key != ? AND creationDate >= ?", newest.key, newest.created_at.to_s(:soap)], limit)
    end
    
    def fetch_and_create(conditions, limit=nil)
      keys = ProsperAPIClient.query('Listing', conditions, nil, ['key'])
      keys = keys.reverse.first(limit) if limit
      return [] if keys.empty?
      listings = ProsperAPIClient.retrieve('Listing', keys.map(&:key), nil, API_TO_MODEL.keys)
      listings.map { |listing| create(attributes_from_listing(listing)) }
    end
  end
  
private
  def ensure_times_are_utc
    [:end_date, :start_date, :created_at, :updated_at].each { |time|  }
  end
end
